const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class Promise {
    promiseState = PENDING
    promiseResult = undefined
    #callbacks = []

    constructor(executor) {
        const resolve = (value) => {
            if (this.promiseState === PENDING) {
                this.promiseState = FULFILLED
                this.promiseResult = value
                this.#callbacks.forEach(({ onResolved }) => onResolved())
            }
        }
        const reject = (reason) => {
            if (this.promiseState === PENDING) {
                this.promiseState = REJECTED
                this.promiseResult = reason
                this.#callbacks.forEach(({ onRejected }) => onRejected())
            }
        }

        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }

    #handleCallback(callback, resolve, reject) {
        try {
            const res = callback(this.promiseResult)
            if (res instanceof Promise) {
                res.then(
                    value => resolve(value),
                    reason => reject(reason),
                )
            } else {
                resolve(res)
            }
        } catch (error) {
            reject(error)
        }
    }

    then(onResolved, onRejected) {
        return new Promise((resolve, reject) => {
            typeof onResolved !== 'function' && (onResolved = value => value)
            typeof onRejected !== 'function' && (onRejected = reason => { throw reason })
            switch (this.promiseState) {
                case FULFILLED:
                    this.#handleCallback(onResolved, resolve, reject)
                    break;

                case REJECTED:
                    this.#handleCallback(onRejected, resolve, reject)
                    break;

                case PENDING:
                    this.#callbacks.push({
                        onResolved: () => this.#handleCallback(onResolved, resolve, reject),
                        onRejected: () => this.#handleCallback(onRejected, resolve, reject),
                    })
                    break;

                default:
                    break;
            }
        })
    }

    catch(callback) {
        return this.then(null, callback)
    }

    // callback:最终执行的回调
    // 回调不接收参数
    // 回调返回值为非Promise或成功的Promise,后续then不接收其返回值
    // 回调返回值为失败的Promise,后续then失败的回调会被执行并接收其返回值
    finally(callback) {
        const onResolved = () => {
            callback()
            return this.promiseResult
        }

        const onRejected = () => {
            callback()
            throw this.promiseResult
        }
        return this.then(onResolved, onRejected)
    }

    // 类的静态方法
    // 所有promise都成功返回成功的结果数组,有一个失败返回第一个失败的结果
    static all(promises) {
        let stateChangedNum = 0 // 状态已改变的promise数量
        const result = []
        return new Promise((resolve, reject) => {
            promises.forEach((e, index) => {
                if (e instanceof Promise) {
                    e.then(value => {
                        result[index] = value
                        stateChangedNum++
                        if (stateChangedNum === promises.length) {
                            resolve(result)
                        }
                    }, reason => {
                        reject(reason)
                    })
                } else {
                    result[index] = e
                    stateChangedNum++
                }
            })
        })
    }

    // 返回最快一个状态改变的promise结果
    static race(promises) {
        return new Promise((resolve, reject) => {
            promises.forEach(e => {
                if (e instanceof Promise) {
                    e.then(value => {
                        resolve(value)
                    }, reason => {
                        reject(reason)
                    })
                } else {
                    resolve(e)
                }
            })
        })
    }

    // 返回第一个成功的promise结果,如果全部失败则返回AggregateError
    static any(promises) {
        let stateChangedNum = 0 // 状态已改变的promise数量
        return new Promise((resolve, reject) => {
            promises.forEach(e => {
                if (e instanceof Promise) {
                    e.then(value => {
                        resolve(value)
                    }, reason => {
                        stateChangedNum++
                        if (stateChangedNum === promises.length) {
                            throw 'AggregateError: All promises were REJECTED'
                        }
                    })
                } else {
                    resolve(e)
                }
            })
        })
    }

    static resolve(value) {
        return new Promise((resolve, reject) => {
            resolve(value)
        })
    }

    static reject(value) {
        return new Promise((resolve, reject) => {
            reject(value)
        })
    }
    // allSettled
}

export default Promise